package com.gitee.wsl.mathematics.matrix.mat3

import com.gitee.wsl.mathematics.matrix.A
import com.gitee.wsl.mathematics.matrix.M
import com.gitee.wsl.mathematics.matrix.Matrix
import com.gitee.wsl.mathematics.matrix.MatrixD
import com.gitee.wsl.mathematics.matrix.MatrixF
import com.gitee.wsl.mathematics.matrix.N
import com.gitee.wsl.mathematics.matrix.SquareMatrix
import com.gitee.wsl.mathematics.matrix.mat2.Matrix2
import com.gitee.wsl.mathematics.matrix.mat2.MutableMatrix2
import com.gitee.wsl.mathematics.vector.vec2.Vector2
import com.gitee.wsl.mathematics.vector.vec3.Vector3

interface Matrix3<T:Number,V: Matrix3<T, V, R>,R:Vector3<T,R>>: SquareMatrix<T, V, R> {

    override val rowCount: Int get() = 3
    override val colCount: Int get() = 3

    val m00: T get() = proxy[0]
    val m01: T get() = proxy[1]
    val m02: T get() = proxy[2]
    val m10: T get() = proxy[3]
    val m11: T get() = proxy[4]
    val m12: T get() = proxy[5]
    val m20: T get() = proxy[6]
    val m21: T get() = proxy[7]
    val m22: T get() = proxy[8]

    override val trace get() = m00 + m11 + m22

    override val m: List<Vector3<T, R>>

    override val n: List<Vector3<T, R>>

    //override fun createVec(indexRage: IntRange): Vector3<T, R>

    override fun toMutable(): MutableMatrix3<T, V, R>

    override fun createVec(indexes: List<Int>): Vector3<T, R>

    override operator fun M.get(row: Int) = createVec(rowIndexes(row))

    override operator fun N.get(col: Int) = createVec(colIndexes(col))

    operator fun A.get(row: Int, col: Int):Matrix2<T, *, *> = TODO()

    /** Calculate the matrix determinant using the Laplace formula. */
    override val det get() =
                m00 * (m22 * m11 - m12 * m21) +
                m01 * (m12 * m20 - m22 * m10) +
                m02 * (m21 * m10 - m11 * m20)

    fun createVec2(x:T,y:T):Vector2<T,*>

    fun createMat2(block:(MutableMatrix2<T, *, *>)->Unit): Matrix2<T, *, *>

    fun create(
       m00: T=zero, m01: T=zero,m02: T=zero,
       m10: T=zero, m11: T=zero,m12: T=zero,
       m20: T=zero, m21: T=zero,m22: T=zero
    ):V

    fun copy(
        m00: T?=null, m01: T?=null, m02: T?=null,
        m10: T?=null, m11: T?=null, m12: T?=null,
        m20: T?=null, m21: T?=null, m22: T?=null
    ) = create(
        m00 ?: this.m00,
        m01 ?: this.m01,
        m02 ?: this.m02,
        m10 ?: this.m10,
        m11 ?: this.m11,
        m12 ?: this.m12,
        m20 ?: this.m20,
        m21 ?: this.m21,
        m22 ?: this.m22
    )


    override fun times(other: V): V {
        fun f(x: Int, y: Int): T {
            return this[0, y] * other[x, 0] + this[1, y] * other[x, 1] + this[2, y] * other[x, 2]
        }
        return create(
            f(0, 0), f(1, 0), f(2, 0),
            f(0, 1), f(1, 1), f(2, 1),
            f(0, 2), f(1, 2), f(2, 2),
        )
    }
    /*create(
        m00 * other.m00 + m01 * other.m10 + m02 * other.m20,
        m00 * other.m01 + m01 * other.m11 + m02 * other.m21,
        m00 * other.m02 + m01 * other.m12 + m02 * other.m22,
        m10 * other.m00 + m11 * other.m10 + m12 * other.m20,
        m10 * other.m01 + m11 * other.m11 + m12 * other.m21,
        m10 * other.m02 + m11 * other.m12 + m12 * other.m22,
        m20 * other.m00 + m21 * other.m10 + m22 * other.m20,
        m20 * other.m01 + m21 * other.m11 + m22 * other.m21,
        m20 * other.m02 + m21 * other.m12 + m22 * other.m22
    )*/



    override val adjoin: V
        get() =  create(
            m22 * m11 - m12 * m21, (-m22 * m01 + m02 * m21), (m12 * m01 - m02 * m11),
            -m22 * m10 + m12 * m20, (m22 * m00 - m02 * m20), (-m12 * m00 + m02 * m10),
            m21 * m10 - m11 * m20, (-m21 * m00 + m01 * m20), (m11 * m00 - m01 * m10)
        )
}

interface Matrix3F<V: Matrix3<Float, V, R>,R:Vector3<Float,R>>: Matrix3<Float, V, R>, MatrixF<V, R>

interface Matrix3D<V: Matrix3<Double, V, R>,R:Vector3<Double,R>>: Matrix3<Double, V, R>, MatrixD<V, R>